package com.hqy.oauth.service.inpl;

import com.hqy.oauth.dto.AuthToken;
import com.hqy.oauth.enums.ReturnCodeEnum;
import com.hqy.oauth.expection.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.*;
import com.hqy.oauth.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.util.Base64;
import java.util.Map;

@Service
public class LoginServiceImpl implements LoginService {

    private static final Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);

    // OAuth2认证相关常量
    private static final String GRANT_TYPE = "grant_type";
    private static final String ACCESS_TOKEN_KEY = "access_token";
    private static final String REFRESH_TOKEN_KEY = "refresh_token";
    private static final String JTI_KEY = "jti";
    private static final String TOKEN_ENDPOINT = "/oauth/token";
    private static final String AUTH_HEADER_PREFIX = "Basic ";

    private static final String FORM_USERNAME = "username";
    private static final String FORM_PASSWORD = "password";

    private static final String HEADER_AUTHORIZATION = "Authorization";

    private static final String LOG_PREFIX = "[AUTH-SERVICE][LoginServiceImpl]";

    // 注入负载均衡客户端
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${auth.clientId}")
    private String clientId;

    @Value("${auth.clientSecret}")
    private String clientSecret;

    @Value("${auth.grantType}")
    private String grantType;

    @Value("${spring.application.name}")
    private String applicationName;

    /**
     * 登录接口
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public AuthToken login(String username, String password) throws BusinessException{
        // 1. 参数校验
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            logger.error("{} 用户名或密码为null", LOG_PREFIX);
            throw new BusinessException(ReturnCodeEnum.INVALID_PARAM.getDesc(), ReturnCodeEnum.INVALID_PARAM);
        }

        try {
            // 2. 构建请求
            //2.1 使用负载均衡客户端获取服务实例URL
            String uri = loadBalancerClient.choose(applicationName).getUri() + TOKEN_ENDPOINT;

            //2.2构建请求参数
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            formData.add(GRANT_TYPE, grantType);
            formData.add(FORM_USERNAME, username);
            formData.add(FORM_PASSWORD, password);

            //2.3: 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            //2.4添加Basic认证头
            String auth = clientId + ":" + clientSecret;
            String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
            headers.set(HEADER_AUTHORIZATION, AUTH_HEADER_PREFIX + encodedAuth);

            //2.5: 创建完整的请求实体
            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);

            // 3. 执行认证请求
            ResponseEntity<Map> exchange;
            try {
                exchange = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, Map.class);
            } catch (HttpClientErrorException.Unauthorized e) {
                // 401 认证失败
                logger.error("{} 认证失败，账号或密码错误: {}", LOG_PREFIX, e.getResponseBodyAsString());
                throw new BusinessException(ReturnCodeEnum.LOGIN_ACCOUNT_ERROR);
            } catch (HttpClientErrorException e) {
                // 其他4xx错误
                logger.error("{} 认证服务错误: {} - {}", LOG_PREFIX, e.getStatusCode(), e.getStatusText());
                throw new BusinessException(ReturnCodeEnum.SERVICE_ERROR);
            } catch (Exception e) {
                // 其他未知异常
                logger.error("{} 认证系统异常: {}", LOG_PREFIX, e.getMessage(), e);
                throw new BusinessException(ReturnCodeEnum.SYSTEM_ERROR);
            }


            // 4. 处理响应
            Map<String, Object> body = exchange.getBody();
            if (CollectionUtils.isEmpty(body)) {
                logger.error("{} 认证服务调用返回空响应" ,LOG_PREFIX);
                throw new BusinessException(ReturnCodeEnum.SERVICE_ERROR.getDesc(), ReturnCodeEnum.SERVICE_ERROR);
            }

            // 5. 提取令牌
            AuthToken authToken = new AuthToken();
            authToken.setAccessToken(getSafeString(body, ACCESS_TOKEN_KEY));
            authToken.setRefreshToken(getSafeString(body, REFRESH_TOKEN_KEY));
            authToken.setJti(getSafeString(body, JTI_KEY));

            if (StringUtils.isBlank(authToken.getAccessToken())) {
                logger.error("{} 认证服务返回无效令牌, username = {}", LOG_PREFIX, username);
                throw new BusinessException(ReturnCodeEnum.SERVICE_ERROR.getDesc(), ReturnCodeEnum.SERVICE_ERROR);
            }

            return authToken;
        } catch (BusinessException e) {
            logger.error("{}认证失败 : {}", LOG_PREFIX, e.getMessage());
            throw e;
        }
    }

    private String getSafeString(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : null;
    }
}
